var PostMessager = (function () {
  'use strict';

  function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
      throw new TypeError("Cannot call a class as a function");
    }
  }

  function _defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
  }

  function _defineProperty(obj, key, value) {
    if (key in obj) {
      Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
      });
    } else {
      obj[key] = value;
    }

    return obj;
  }

  var _messageId = 0;
  var generateMessageId = function generateMessageId() {
    return ++_messageId;
  };
  var log = function log() {
    var _console;

    return (_console = console).log.apply(_console, arguments);
  };
  var warn = function warn() {
    var _console2;

    return (_console2 = console).warn.apply(_console2, arguments);
  };
  var devLog = function devLog(message) {
    var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'default';

    if (process.env.NODE_ENV !== 'production') {
      log("".concat(name, "\uFF1A"), message);
    }
  };
  /**
   * Takes a URL and returns the origin
   * @param  {String} url The full URL being requested
   * @return {String}     The URLs origin
   */

  var resolveOrigin = function resolveOrigin() {
    var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
    var a = document.createElement('a');
    a.href = url;
    var protocol = a.protocol.length > 4 ? a.protocol : window.location.protocol;
    var host = a.host.length ? a.port === '80' || a.port === '443' ? a.hostname : a.host : window.location.host;
    return a.origin || "".concat(protocol, "//").concat(host);
  };
  var SupportPostMessage = function SupportPostMessage(win) {
    return 'postMessage' in win;
  };
  /* 
    可以参考: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
  */

  var postMessage = function postMessage(win, data) {
    var targetOrigin = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';

    if (SupportPostMessage(win)) {
      win.postMessage(data, targetOrigin);
    } else {
      log('您的浏览器不支持postMessage');
    }
  };
  /**
   * Ensures that a message is safe to interpret
   * @param  {Object} message The postmate message being sent
   * @param  {String|Boolean} allowedOrigin The whitelisted origin or false to skip origin check
   * @return {Boolean}
   */

  /* const messageTypes = {
    handshake: 1,
    'handshake-reply': 1,
    call: 1,
    emit: 1,
    reply: 1,
    request: 1,
  }

  export const sanitize = (message: MessageEvent, allowedOrigin: string) => {
    if (
      typeof allowedOrigin === 'string' &&
      message.origin !== allowedOrigin
    ) return false
    if (!message.data) return false
    if (
      typeof message.data === 'object' &&
      !('postmate' in message.data)
    ) return false
    if (message.data.type !== messageType) return false
    // if (!messageTypes[message.data.postmate]) return false
    return true
  } */

  /* const checkBuiltEvent = function(event: string): boolean {
    return ['receive'].indexOf(event) > -1
  } */
  var checkOriginEq = function checkOriginEq(origin, targetOrigin) {
    return resolveOrigin(origin) === resolveOrigin(targetOrigin);
  };

  var PostMessager = /*#__PURE__*/function () {
    // 标识
    // 标识
    function PostMessager(config) {
      _classCallCheck(this, PostMessager);

      _defineProperty(this, "host", window);

      _defineProperty(this, "target", null);

      _defineProperty(this, "origin", '');

      _defineProperty(this, "id", '');

      _defineProperty(this, "targetId", '');

      _defineProperty(this, "listenersMap", {
        receive: {
          listeners: []
        }
      });

      if (!SupportPostMessage(window)) {
        warn('您的浏览器不支持postMessage');
        return;
      }

      if (!config.id) {
        warn('请输入name属性作为标识');
        return;
      }

      this.id = config.id;
      this.host = config.host || window;
      this.target = config.target;
      this.targetId = config.targetId;
      this.origin = config.origin || resolveOrigin(); // 绑定事件

      this.initListener();
    }

    _createClass(PostMessager, [{
      key: "initListener",
      value: function initListener() {
        var _this = this;

        // 初始化事件绑定
        var listenersHandler = function listenersHandler(event) {
          if (!checkOriginEq(_this.origin, event.origin)) return; // 触发事件

          var _event$data = event.data,
              toStr = _event$data.toStr,
              eventName = _event$data.eventName,
              content = _event$data.content; // 验证id或者to属性

          if (toStr === _this.id) {
            _this._emit(eventName, content, event);
          }
        };

        this.host.addEventListener('message', listenersHandler, false);
      }
      /* 
        本质上,send方法就是出发一次once事件
      */

    }, {
      key: "send",
      value: function send(id, message, config) {
        if (!this.target) {
          warn('缺少target参数');
          return;
        }

        var orgin = (config === null || config === void 0 ? void 0 : config.origin) || '*';
        var _message = {
          content: message,
          toStr: id,
          eventName: 'receive',
          fromStr: this.id,
          id: generateMessageId()
        };
        postMessage(this.target, _message, orgin);
      }
    }, {
      key: "on",
      value: function on(eventName, listener) {
        var evtObj = this.listenersMap[eventName];

        if (!evtObj) {
          PostMessager.createListenerObject(this.listenersMap, eventName);
          evtObj = this.listenersMap[eventName];
        }

        if (listener) {
          var _evtObj$listeners;

          (_evtObj$listeners = evtObj.listeners) === null || _evtObj$listeners === void 0 ? void 0 : _evtObj$listeners.push(listener);
        }
      }
    }, {
      key: "off",
      value: function off(eventName, listener) {
        var listeners = this.listenersMap[eventName].listeners;

        if (listeners) {
          var index = listeners.findIndex(function (cb) {
            return listener === cb;
          });

          if (index != -1) {
            listeners.splice(index, 1);
          }
        }
      }
    }, {
      key: "once",
      value: function once(eventName, listener) {
        var _this2 = this;

        var cb = function cb(data, event) {
          listener.call(_this2, data, event);

          _this2.off(eventName, cb);
        };

        this.on(eventName, cb);
      }
    }, {
      key: "targetEmit",
      value: function targetEmit(eventName, data, event) {
        if (!this.target) {
          warn('缺少target参数');
          return;
        }

        var _message = {
          content: data,
          toStr: this.targetId,
          eventName: eventName,
          fromStr: this.id,
          event: event,
          id: generateMessageId()
        };
        postMessage(this.target, _message, this.origin || '*');
      }
    }, {
      key: "_emit",
      value: function _emit(eventName, data, event) {
        var _evtObj$listeners2,
            _this3 = this;

        var evtObj = this.listenersMap[eventName];

        if (!evtObj) {
          devLog('没有这个事件');
          return;
        }

        (_evtObj$listeners2 = evtObj.listeners) === null || _evtObj$listeners2 === void 0 ? void 0 : _evtObj$listeners2.forEach(function (cb) {
          cb.call(_this3, data, event);
        });
      }
    }], [{
      key: "createListenerObject",
      value: function createListenerObject(listenersMap, evtName) {
        listenersMap[evtName] = {
          listeners: []
        };
      }
    }]);

    return PostMessager;
  }();

  return PostMessager;

}());
